--Inport: PMEngine, PrivateDB, ProfileDB, GlobalDB
local PMEngine, L, PrivateDB, ProfileDB, GlobalDB = unpack(select(2, ...)); 
local GM = PMEngine:NewModule('GuildMod', 'AceTimer-3.0', 'AceHook-3.0', 'AceEvent-3.0')
PMEngine.GuildMod = GM

local DEFAULT_WIDTH = 890;
local DEFAULT_HEIGHT = 768;

local GUILD_TOTAL

local who_pending = false
local recent_queries = {}
local invite_list = {}

local test_invite_keywords = {'invite','inv','ginvite',}
local test_member_keywords = {'superhero','superisawesome',}

local test_default_rank = 8
local test_default_officerNote = "n/a"
local test_rank_list = {
	{ rank = 4, toRank = 7, rankPassword = 'awesome', officerNote = 'goodbad'},
	{ rank = 3, toRank = 3, rankPassword = 'awesomeo', officerNote = 'good'},
}

local test_
--local AC = LibStub("AceConfig-3.0")
--local ACD = LibStub("AceConfigDialog-3.0")

function GM:findMatch(str, patterns, caseSensitive)
    local ret
    for _, pattern in pairs(patterns) do
        if caseSensitive then
            ret = {string.find(str, pattern)}
        else
            ret = {string.find(string.lower(str), pattern)}
        end 
        if ret[1] then
            return unpack(ret)
        end
    end
    return nil
end
function GM:HandleWhipser(event, msg, sender)
	--if sender ~= UnitName("player") then
		msg = msg:lower()

		-- Check to see if a keyword was matched in this whisper
		if self:findMatch(msg,test_invite_keywords, false) then
			-- Check to see if this person has recently qued an invite
			local found_flag = false
			for i=1 , #recent_queries do
				if recent_queries[i].player == sender then found_flag = true end
			end
			if found_flag then 
				SendChatMessage("You've already requested an nvite." ,"WHISPER" ,nil, sender);
				return false
			end
			-- Check to see if a masterKey was included  with invite request
			local keyFound = false
			if self:findMatch(msg,test_member_keywords, false) then keyFound = true; end
			-- Send the whisper response
			SendChatMessage("One moment please, while i check to see if you are in a guild." ,"WHISPER" ,nil, sender);
			-- insert the sender in to the recent queries table
			table.insert(recent_queries, {
				player = sender,
				guildCheck = false,
				hasGuild = false,
				masterKey = keyFound,
				awaitingResponse = false,
				inviteStep = 1,
				lastResponse = GetTime(),
				mainName = "",
				rankFound = false,
				rankIndex = 0,
				rank = 0
			})
			return
		end
		if #recent_queries > 0 then
			for i=1, #recent_queries do
				-- Step 5: Run if sender is in the query list and inviteStep is 2 and we are awaiting a response
				if recent_queries[i].player == sender and recent_queries[i].inviteStep == 2 and recent_queries[i].awaitingResponse == true then 
					-- Check if the name the player whispered is currently in guild
					local n = GetNumGuildMembers();
					for x=1, n do
						local name, rank, rankIndex, level, class, zone, note, officernote, online, status, classFileName, achievementPoints, achievementRank, isMobile, canSoR = GetGuildRosterInfo(x);
						name = strlower(name)
						if name  == strlower(msg) then
							-- Check to see if the player's rank is in the rank list
							for o=1, #test_rank_list do
								if GuildControlGetRankName(test_rank_list[o].rank) == rank then
									-- if rank is found set rank index, change invite step and tell onupdate we are no longer awaiting a response
									recent_queries[i].mainName = name
									recent_queries[i].rankIndex = o
									recent_queries[i].rankFound = true
									recent_queries[i].inviteStep = 3
									recent_queries[i].awaitingResponse = false
									return
								end
							end
							-- if player is not in the list, take to next step without rankIndex
							recent_queries[i].mainName = name
							recent_queries[i].inviteStep = 3
							recent_queries[i].awaitingResponse = false
							return		
						end
					end
					local guildName =  GetGuildInfo('player')
					SendChatMessage("That character was not found in "..guildName..". Please try again." ,"WHISPER" ,nil, sender);
					table.remove(recent_queries, i)
					return
				end
				-- Step 7: Parse the recieved password
				if recent_queries[i].player == sender and recent_queries[i].inviteStep == 4 and recent_queries[i].awaitingResponse == true then 
					-- check to see if msg is the rank password
					if test_rank_list[recent_queries[i].rankIndex].rankPassword == strlower(msg) then
						recent_queries[i].inviteStep = 5
						recent_queries[i].awaitingResponse = false
						return
					else
						SendChatMessage("Incorrect password. Please try again." ,"WHISPER" ,nil, sender);
						table.remove(recent_queries, i)
						return
					end
				end
			end
		end
		-- Invite casuals here
		--[[table.insert(invite_list, {
			player = sender,
			rank = 4,
			message = msg
		})]]
	
end

function GM:OnUpdate()
	-- Show/Hide the invite button
	if #invite_list ~= 0 then
		GM.InviteButton:Show()
	else
		GM.InviteButton:Hide()
	end

	-- Check to see if we've had any recent queries to join the guild 
	if #recent_queries > 0 then
		-- Internal: Remove player from que if past wait time
		for i=1, #recent_queries do
			if recent_queries[i].lastResponse+60 < GetTime() then 
				SendChatMessage("Your request has timed out." ,"WHISPER" ,nil, recent_queries[i].player);
				table.remove(recent_queries, i)
				return
			end
		end
		-- Step 1: Initial guild checker
		-- This will only run if the who_pending flag is set to false
		if not who_pending then
			-- check to see if anyone in the recent_queries table has not been check for guild
			for i=1, #recent_queries do
				if not recent_queries[i].guildCheck then 
					-- Send a who request to the server for guild checking
					SendWho(recent_queries[i].player)
					-- who_pending is set to true so we do not send multiple who's for the same person.
					-- This is later handled by CHAT_MSG_SYSTEM
					who_pending = true
					return
				end
			end
		end

		for i=1, #recent_queries do
			if recent_queries[i].guildCheck then
				-- Step 2: Handle response whisper and push next step
				-- Check to see if player returned guilded
				if recent_queries[i].hasGuild then 
					-- Whisper fail message to player
					SendChatMessage("You are guilded, please /gquit and try again." ,"WHISPER" ,nil, recent_queries[i].player);
					table.remove(recent_queries, i)
					return
				end
				-- Step 3: Check to see if keyword was added and either add to default invite que or push to next step
				if not recent_queries[i].masterKey then 
					-- Send invite whisper
					SendChatMessage("You have been added to the nvite que. You will be nvited as soon as possible." ,"WHISPER" ,nil, recent_queries[i].player);
					table.insert(invite_list, {
						player = recent_queries[i].player,
						rank = 0,
						officerNote = test_default_officerNote,
						invited = false
					})
					table.remove(recent_queries, i)
					return
				else
					-- Step 4: Ask for characters main in guild.
					if recent_queries[i].inviteStep == 1 and not recent_queries[i].awaitingResponse then
						SendChatMessage("What is the exact name of your main character in guild?" ,"WHISPER" ,nil, recent_queries[i].player);
						recent_queries[i].inviteStep = 2
						recent_queries[i].awaitingResponse = true
						return
					end
					-- Step 6: Ask for characters rank password
					if recent_queries[i].inviteStep == 3 and not recent_queries[i].awaitingResponse then
						-- If no rank was found, add player to invite list with default rank WITH an officer note.
						if not recent_queries[i].rankFound then 
							SendChatMessage("You have been added to the nvite que. You will be nvited as soon as possible." ,"WHISPER" ,nil, recent_queries[i].player);
							table.insert(invite_list, {
								player = recent_queries[i].player,
								rank = 0,
								officerNote = test_default_officerNote,
								mainName = recent_queries[i].mainName,
								invited = false
							})
							table.remove(recent_queries, i)
							return
						end
						local rankName = GuildControlGetRankName(test_rank_list[recent_queries[i].rankIndex].rank)
						SendChatMessage("What is the password for the "..rankName.." rank?","WHISPER" ,nil, recent_queries[i].player);
						recent_queries[i].inviteStep = 4
						recent_queries[i].awaitingResponse = true
						return
					end
					if recent_queries[i].inviteStep == 5 and not recent_queries[i].awaitingResponse then
						SendChatMessage("You have been added to the nvite que. You will be nvited as soon as possible." ,"WHISPER" ,nil, recent_queries[i].player);
						table.insert(invite_list, {
							player = recent_queries[i].player,
							rank = recent_queries[i].rankIndex,
							officerNote = test_rank_list[recent_queries[i].rankIndex].officerNote,
							mainName = recent_queries[i].mainName,
							invited = false
						})
						table.remove(recent_queries, i)
						return
					end
				end
			end
		end
	end
end

function GM:HandleGuildUpdate(event, ...)
	local guild_total = GetNumGuildMembers()
	if guild_total ~= GUILD_TOTAL then
		if #invite_list > 0 then 
			for i=1, guild_total do
				local name, rank, rankIndex = GetGuildRosterInfo(i)
				name = strlower(name)
				for n=1, #invite_list do
					if name  == strlower(invite_list[n].player) and invite_list[n].invited then
						if invite_list[n].rank ~= 0 then
							rank_array = test_rank_list[invite_list[n].rank]
							if (rankIndex+1) ~= rank_array.rank then
								SetGuildMemberRank(i, rank_array.rank);
							end
							GuildRosterSetOfficerNote(i, rank_array.officerNote)
							table.remove(invite_list, n)
						else
							if (rankIndex+1) ~= test_default_rank then
								
								SetGuildMemberRank(i, test_default_rank);
							end
							GuildRosterSetOfficerNote(i, test_default_officerNote)
							table.remove(invite_list, n)
						end
					end
				end
			end
		end
		GUILD_TOTAL = guild_total
	end
end

function GM:OnClick(self, btn) 
	for i=1, #invite_list do
		if not invite_list[i].invited then
			GuildInvite(invite_list[i].player)
			invite_list[i].invited = true
		end
	end
end

function GM:HandleSystemMessage(event, message)
	message = tostring(message:lower())
	
	if GetWhoInfo(1) then
		if string.find(message, string.lower("total"), 1, true) then return false end
		-- Check to see if the Who()'d player is in a guild
		if select(2, GetWhoInfo(1)) ~= "" then
			-- Set recent_queries to show that player is guilded
			for i=1, #recent_queries do
				if recent_queries[i].player == select(1, GetWhoInfo(1)) then recent_queries[i].hasGuild = true; recent_queries[i].guildCheck = true; end
			end
		else
			-- Set recent_queries to show that player is NOT guilded
			for i=1, #recent_queries do
				if recent_queries[i].player == select(1, GetWhoInfo(1)) then recent_queries[i].hasGuild = false; recent_queries[i].guildCheck = true; end
			end
		end
		-- Reset Who info
		SendWho(".")
	else
		--  After Reset, allow next who
		who_pending = false
	end
end

function GM:Initialize()
	--if true then return end
	--AC:RegisterOptionsTable('ChatSpam', CS.Options)
	--ACD:SetDefaultSize('ChatSpam', DEFAULT_WIDTH, DEFAULT_HEIGHT)

	GUILD_TOTAL = GetNumGuildMembers()

	self:RegisterEvent("CHAT_MSG_WHISPER", "HandleWhipser")
	self:RegisterEvent("GUILD_ROSTER_UPDATE", "HandleGuildUpdate")
	self:RegisterEvent("CHAT_MSG_SYSTEM", "HandleSystemMessage")

	self.InviteButton = CreateFrame('Button', 'InviteButton', PMEngine.UIParent)
	self.InviteButton:Point('TOP', "MMHolder", 'BOTTOM', 0, -3)
	self.InviteButton:SetSize(100,50)
	self.InviteButton:SetTemplate('Default', true)
	self.InviteButton:SetScript('OnClick', GM.OnClick)
	self.InviteButton:Hide()

	self.Frame = CreateFrame("frame")
	self.Frame:SetScript("OnUpdate", GM.OnUpdate)
end

PMEngine:RegisterModule(GM:GetName())